home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
UNITRE11.ARJ
/
UNITREE.DOC
next >
Wrap
Text File
|
1992-06-24
|
9KB
|
227 lines
UNITREE -- display the UNIT dependency TREE from a Turbo Pascal compilation.
Version 1.1.
Copyright (C) 1992 J. C. Rice. All Rights Reserved.
Individuals and business corporations may use UNITREE free of charge. You
may neither sell it nor charge for distributing it without express consent of
the copyright holder.
rice@zizania.cray.com
---------------------------------------------------
*** How to use it ***
TPC /B [other options] main.pas | UNITREE > report.fil
or TPC /B [other options] main.pas | UNITREE | viewer.exe
where:
other options are whatever else you need to compile your program
main.pas is the name of your main program
report.fil is the file you want the dependency tree written to
viewer.exe is the name of your favorite display program (LIST, LESS,
etc.)
If you don't redirect the output of UNITREE, you'll see it on the screen.
There are no command line parameters or options. TPCX can be substituted for
TPC. You can redirect the output of TPC to a file and later redirect it as
input to unitree.
---------------------------------------------------
*** Why to use it ***
I'm not going to explain UNITs and USES in this brief file. If you aren't
already familiar with them, read chapter 3 of Borland's TP User's Guide --
but if you aren't already familiar with them, odds are you don't need
unitree.
Unitree displays the *compilation-ordered* dependency tree of units. It does
not display the complete graph of all interdependencies; rather, it shows how
the TP compiler finds and resolves the USES statements, and in what order.
To see what that means, consider the following trivial example, consisting
of a main program and four units:
program main; unit math; unit stats; unit ext_prec; unit prob_lib;
uses uses uses {uses none} {uses none}
stats, ext_prec; prob_lib,
math; math;
Here's what Turbo Pascal does in response to a full build of main.pas:
step .PAS files open
1. Open main.pas main
2. Note the "uses stats" main
3. Open stats.pas main stats
4. Note the "uses prob_lib" main stats
5. Open prob_lib.pas main stats prob_lib
6. Compile prob_lib.pas main stats prob_lib
7. Close prob_lib.pas main stats
8. Return to stats.pas main stats
9. Note the "uses math" main stats
10. Open math.pas main stats math
11. Note the "uses ext_prec" main stats math
12. Open ext_prec.pas main stats math ext_prec
13. Compile ext_prec.pas main stats math ext_prec
14. Close ext_prec.pas main stats math
15. Return to math.pas main stats math
16. Compile math.pas main stats math
17. Close math.pas main stats
18. Return to stats.pas main stats
19. Compile stats.pas main stats
20. Close stats.pas main
21. Return to main.pas main
22. Note the "uses math" refers
to an already-compiled unit main
23. Compile main.pas main
24. Close main.pas
And here is the output of unitree for this compilation:
MAIN
└─STATS (4)
├─PROB_LIB (1)
└─MATH (3)
└─EXT_PREC (2)
(Ignore the parenthetical numbers for now). As you can see, at one point in
the compilation there were four modules in some intermediate stage of
compilation. Now look what happens if we make a single change: switch the
order of the units in the main program's USES statement:
program main; unit math; unit stats; unit ext_prec; unit prob_lib;
uses uses uses
math, {***} ext_prec; prob_lib,
stats;{***} math;
step (some omitted .PAS files open
for brevity)
1. Open main.pas main
2. Open math.pas main math
3. Open ext_prec.pas main math ext_prec
4. Close ext_prec.pas main math
5. Close math.pas main
6. Open stats.pas main stats
7. Open prob_lib.pas main stats prob_lib
8. Close prob_lib.pas main stats
9. math already compiled main stats
10. Close stats.pas main
11. Close main.pas
Here is the output of unitree for this compilation:
MAIN
├─MATH (2)
│ └─EXT_PREC (1)
└─STATS (4)
└─PROB_LIB (3)
Now the maximum "compilation depth" is three modules, rather than four.
While this is obvious on inspection of these five trivial modules, imagine a
project of 50+ units, each of which might use a dozen units -- not so easy to
make the necessary mental picture any more. And definitely not easy to make
this further refinement, as shown by the trivial example again:
program main; unit math; unit stats; unit ext_prec; unit prob_lib;
uses uses uses
ext_prec,{***} ext_prec; prob_lib,
prob_lib,{***} math;
math,
stats;
Here is the output of unitree for this compilation:
MAIN
├─EXT_PREC (1)
├─PROB_LIB (2)
├─MATH (3)
└─STATS (4)
By including units (ext_prec, prob_lib) in the main program that are *not*
directly used, the compilation depth shrinks to two.
Why the fuss over compilation depth? Because the compilation depth of a
large project may cause TP to exceed MS-DOS's limit on the number of open
files. The result is compile-time error 13, "too many open files." The
Borland manuals diagnose this as an insufficient FILES= setting in
CONFIG.SYS, but it's more likely to result from USES statements that aren't
ordered to best advantage.
Your strategy, then, is to move "leaf" units -- those that don't rely on any
others -- to the beginning of the main program's USES statement. Then use
the output of unitree to find other units that depend just on leaves, and
place those next, etc. [Remember to leave the Borland overlay unit and the
unit with your ovrinit call *before* anything that's overlaid.] You can also
use unitree to look for the highest compilation depth (the units farthest to
the right on the output) and try to shorten that path.
There's another interesting consequence to the order in which Turbo Pascal
resolves compilation dependencies: it determines the order in which unit
intializtion code will be executed. Observe the unitree output for the three
examples, along with the runtime output of the program:
graph execution
First example:
MAIN initializing prob_lib
└─STATS (4) initializing ext_prec
├─PROB_LIB (1) initializing math
└─MATH (3) initializing stats
└─EXT_PREC (2) executing main
Second example:
MAIN initializing ext_prec
├─MATH (2) initializing math
│ └─EXT_PREC (1) initializing prob_lib
└─STATS (4) initializing stats
└─PROB_LIB (3) executing main
Third example:
MAIN initializing ext_prec
├─EXT_PREC (1) initializing prob_lib
├─PROB_LIB (2) initializing math
├─MATH (3) initializing stats
└─STATS (4) executing main
You can see that the initialization code is placed into sequence at the time
each unit's compilation is finally resolved. In the first example, for
instance, prob_lib is the first unit to be completely compiled, and its
initialization code runs first. The numbers in parentheses, shown after the
unit names, indicate the order in which initialization code will be executed.
A final note: be sure to use the /B (build all) command line option on
TPC/TPCX, to get the full tree. If you use /M (make as needed) you'll still
get the output, but there's no telling what pieces of the picture might be
omitted.
---------------------------------------------------
*** History ***
This little program is the result of a conversation I had with the
ever-reliable Duncan Murdoch, about compilation error 13. I appreciate his
advice.
92-06 Version 1.0. Represents nearly 70 minutes of development time, and
almost 10 whole minutes of testing. Seems to work with
TP versions 5.5 and 6.0; no idea about earlier versions.
92-06 Version 1.1. Fixed boneheaded error too embarassing to describe.
Minor symptom: program does not run.
If you use this program, consider dropping me a note to say that it was
helpful or that it wasn't (and why). I'd appreciate it. The address is:
internet: rice@zizania.cray.com
uucp: [backbone]!uunet!cray!rice